
import { EventKeyboard, input, Input, KeyCode, sys } from 'cc';

export interface KeyEvents {
    down?: Function
    press?: Function
    up?: Function
    /* will auto bind, dont config this */
    combine?: KeyCode[]
}

class InputCtrl {
    h = 0
    v = 0
    ratio = 1;
    jump = false;
    rad = 0;
    joystick = false;
    keyMap = new Map<KeyCode, KeyEvents>;
    keyState = new Map<KeyCode, boolean>;
    constructor() {
        if (sys.platform == sys.Platform.DESKTOP_BROWSER) {
            input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
            input.on(Input.EventType.KEY_PRESSING, this.onKeyPress, this);
            input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
            var self = this;
            document.addEventListener('visibilitychange', function () {
                var isHidden = document.hidden;
                if (isHidden) {
                    self.h = self.v = 0;
                    self.ratio = 1;
                }
            });
            this.addKeys([KeyCode.KEY_W,KeyCode.ARROW_UP], {
                down: () => {
                    this.h = 1;
                },
                up: () => {
                    (this.h > 0) && (this.h = 0);
                }
            })
            .addKeys([KeyCode.KEY_S,KeyCode.ARROW_DOWN], {
                down: () => {
                    this.h = -1;
                },
                up: () => {
                    (this.h < 0) && (this.h = 0);
                }
            })
            .addKeys([KeyCode.KEY_A,KeyCode.ARROW_LEFT], {
                down: () => {
                    this.v = -1
                },
                up: () => {
                    (this.v < 0) && (this.v = 0);
                }
            })
            .addKeys([KeyCode.KEY_D,KeyCode.ARROW_RIGHT], {
                down: () => {
                    this.v = 1
                },
                up: () => {
                    (this.v > 0) && (this.v = 0);
                }
            })
            .addKey([KeyCode.CTRL_LEFT, KeyCode.KEY_Z], {
                down: () => {
                    //un-do
                }
            });
        }
    }
    /**
     * @Description: add groups of keys for same function,if you need add groupds of combination, use [[key1,key2],[key3,key4]]
     * @param {KeyCode} keysgroup
     * @param {KeyEvents} event
     * @return {*}
     */
    addKeys(keysgroup: KeyCode[][] | KeyCode[], event: { down?: Function, press?: Function,up?: Function}):InputCtrl {
        keysgroup.forEach((keys) => {
            this.addKey(keys, event);
        })
        return this;
    }

    /**
     * @Description: 
     * @param {KeyCode} keys use array for combination keys use single Keycode for single Key
     * @param {KeyEvents} event
     * @return {*}
     */
    addKey(keys: KeyCode[] | KeyCode, event: KeyEvents) {
        if (typeof keys === "object") {
            event.combine = keys;
            keys.forEach((key) => {
                this.keyMap.set(key, event);
            })
        } else {
            this.keyMap.set(keys, event);
        }
    }

    removeKey(keys: KeyCode[]) {
        keys.forEach((key) => {
            this.keyMap.delete(key);
        })
    }

    onKeyDown(event: EventKeyboard) {
        const keyCode = event.keyCode;
        this.keyState.set(keyCode, true);

        const cb = this.keyMap.get(keyCode);
        if (cb) {
            const combine = cb.combine;
            if (combine) {
                for (var i = 0; i < combine.length; i++) {
                    const key = combine[i];
                    const keystate = this.keyState.get(key);
                    if (!keystate) return;
                }
            }
            if (cb.down) cb.down();
        }
    }
    onKeyPress(event: EventKeyboard) {
        const keyCode = event.keyCode;
        const cb = this.keyMap.get(keyCode);
        if (cb && cb.press) {
            cb.press()
        }
    }

    onKeyUp(event: EventKeyboard) {
        const keyCode = event.keyCode;
        this.keyState.set(keyCode, false);
        const cb = this.keyMap.get(keyCode);
        if (cb && cb.up) {
            cb.up()
        }
    }

}

const ctrlMgr = new InputCtrl;

export default ctrlMgr;
